#ifndef REL_OP_H
#define REL_OP_H

#include "Pipe.h"
#include "DBFile.h"
#include "Record.h"
#include "Function.h"

class RelationalOp {
	public:
		// blocks the caller until the particular relational operator 
		// has run to completion
		virtual void WaitUntilDone () = 0;

		// tell us how much internal memory the operation can use
		virtual void Use_n_Pages (int n) = 0;
};

class SelectFile : public RelationalOp { 

	private:
		pthread_t thread;

		struct  Inputs     {                
			DBFile *inFile;        
			Pipe *outPipe;        
			CNF *cnf;        
			Record *literal;        
			Inputs(DBFile *inpFile, Pipe *outPipeR, CNF *inpCnf, Record *literalR)   
			{        
				inFile = inpFile;          
				outPipe = outPipeR;         
				cnf = inpCnf;            
				literal = literalR;       
			}       
		};  

		static void*  SelectFile_run(void*); 
	public:
		void Run (DBFile &inFile, Pipe &outPipe, CNF &selOp, Record &literal);
		void WaitUntilDone ();
		void Use_n_Pages (int n);

};

class SelectPipe : public RelationalOp {
	private:
		pthread_t thread;

		struct  Inputs     {
			Pipe *inPipe;
			Pipe *outPipe;
			CNF *cnf;
			Record *literal;
			Inputs(Pipe *inPipeR, Pipe *outPipeR, CNF *inpCnf, Record *literalR)
			{
				inPipe = inPipeR;
				outPipe = outPipeR;
				cnf = inpCnf;
				literal = literalR;
			}
		};

		static void*  SelectPipe_run(void*);
	public:
		void Run (Pipe &inPipe, Pipe &outPipe, CNF &selOp, Record &literal) ;
		void WaitUntilDone () ;
		void Use_n_Pages (int n) { }
};

class Project : public RelationalOp { 
	private:
		pthread_t thread;
		struct Inputs 
		{         
			Pipe *inPipe;
			Pipe *outPipe;
			int * AttsToKeep;
			int numAttsToKeep;
			int numAttsRec;    

			Inputs(Pipe *inPipeR, Pipe *outPipeR, int *keepMe, int numAttsInput, int numAttsOutput)      
			{                
				inPipe = inPipeR;     
				outPipe = outPipeR;   
				AttsToKeep = keepMe; 
				numAttsToKeep = numAttsOutput;  
				numAttsRec = numAttsInput;
			}      
		};     
		static void* Project_run(void*);  

	public:
		void Run (Pipe &inPipe, Pipe &outPipe, int *keepMe, int numAttsInput, int numAttsOutput) ;
		void WaitUntilDone () ;
		void Use_n_Pages (int n) { }
};

class Join : public RelationalOp { 
	private:
		pthread_t thread;
		static int runlen;
		struct Inputs
		{
			Pipe *inPipeL;
			Pipe *inPipeR;
			Pipe *outPipe;
			CNF *cnf;
			Record *literal;
			Schema* s1;
			Schema* s2;
			Inputs(Pipe *inPipeLe, Pipe *inPipeRi, Pipe *outPipeR, CNF *selOp, Record *literal, Schema* schema1, Schema* schema2)
			{
				inPipeL = inPipeLe;
				inPipeR= inPipeRi;
				outPipe = outPipeR;
				cnf=selOp;
				literal=literal;
				s1 = schema1;
				s2 = schema2;

			}

		};
		static void* Join_run(void*);
	public:
		void Run (Pipe &inPipeL, Pipe &inPipeR, Pipe &outPipe, CNF &selOp, Record &literal, Schema &s1, Schema &s2);
		void WaitUntilDone ();
		void Use_n_Pages (int n);
};

class DuplicateRemoval : public RelationalOp {
	private:
	private:        
		pthread_t thread;  
		static int runlen;         
		struct Inputs 
		{ 
			Pipe *inPipe;
			Pipe *outPipe;                      
			Schema *sch;
			Inputs(Pipe *inPipeR, Pipe *outPipeR, Schema *mySchema) 
			{ 
				inPipe = inPipeR;
				outPipe = outPipeR;
				sch = mySchema; 
			}   
		};    
		static void* DuplicateRemoval_run(void*); 

	public:
		void Run (Pipe &inPipe, Pipe &outPipe, Schema &mySchema) ;
		void WaitUntilDone () ;
		void Use_n_Pages (int n);
};

class Sum : public RelationalOp {
	private:
		pthread_t thread;      
		struct Inputs
		{            
			Pipe *inPipe;
			Pipe *outPipe;                    
			Function *comp;             
			Inputs(Pipe *inPipeR, Pipe *outPipeR, Function *compute)      
			{                
				inPipe = inPipeR;              
				outPipe = outPipeR;                       
				comp= compute;           
			}        
		};        
		static void* Sum_run(void*);        
	public:       
		void Run (Pipe &inPipe, Pipe &outPipe, Function &computeMe);       
		void WaitUntilDone ();      
		void Use_n_Pages (int n){}
};

class GroupBy : public RelationalOp {

	private:
		pthread_t thread;
		static int runlen;
		struct Inputs
		{
			Pipe *outPipe, *inPipe;
			OrderMaker *grpAttr;
			Function *func;


			Inputs(Pipe *inPip, Pipe *outPip, OrderMaker *groupAtts, Function *computeMe)
			{
				inPipe = inPip;
				outPipe = outPip;
				grpAttr = groupAtts;
				func = computeMe;

			}
		};
		static void* GroupBy_run(void*);
	public:
		void Run (Pipe &inPipe, Pipe &outPipe, OrderMaker &groupAtts, Function &computeMe) ;
		void WaitUntilDone () ;
		void Use_n_Pages (int n) ;
};


class WriteOut : public RelationalOp {
	private:        
		pthread_t thread;    
		struct Inputs
		{            
			Pipe *inPipe;                      
			Schema *sch;                     
			FILE *file;                         
			//   int *count;            
			Inputs(Pipe *inPipeR, Schema *pMySchema, FILE *outFile)            
			{     
				inPipe = inPipeR;                               
				sch = pMySchema;                                
				file = outFile;                               
				// count = cnt;            
			}        
		};        
		static void* WriteOut_run(void*); 
	public:
		void Run (Pipe &inPipe, FILE *outFile, Schema &mySchema);
		void WaitUntilDone () ;
		void Use_n_Pages (int n) { }
};
#endif
